Silhouette analysis
set.seed(322)
k.max <- 10
data <- feature_vector_training
nrow(data)
[1] 3322
sil <- rep(0, k.max)
# Compute the average silhouette width for
# k = 2 to k = 15
for(i in 2:k.max){
km.res <- kmeans(data, centers = i, nstart = 25)
ss <- silhouette(km.res$cluster, dist(data))
sil[i] <- mean(ss[, 3])
}
# Plot the average silhouette width
plot(1:k.max, sil, type = "b", pch = 19,
frame = FALSE, xlab = "Number of clusters k")
abline(v = which.max(sil), lty = 2)

Data training partitions: cold start study
Iteration #1
output_1 <- result$output
output_t_1 <- result$output_t
output_1
gg <- ggplot(data = output_1)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

first_training_sample <- training.sampled_1[1:200,]
ggplot(first_training_sample) + geom_bar(aes(subclass))

class_distribution <- first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

testing_result <- result$testing_result
#testing_result
gg <- ggplot(data = output_t_1)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

output_t_aux_1 <- output_t_1
names(output_t_aux_1) <- c('data_count_t','metric_t')
output_result_1 <- cbind(output_1,output_t_aux_1)
gg <- ggplot(data = output_result_1)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

Iteration #2
output_2 <- result_2$output
output_t_2 <- result_2$output_t
output_2
gg <- ggplot(data = output_2)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

first_training_sample <- training.sampled_2[1:200,]
ggplot(first_training_sample) + geom_bar(aes(subclass))

class_distribution <- first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

testing_result_2 <- result$testing_result
#testing_result
gg <- ggplot(data = output_t_2)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

output_t_aux_2 <- output_t_2
names(output_t_aux_2) <- c('data_count_t','metric_t')
output_result_2 <- cbind(output_2,output_t_aux_2)
gg <- ggplot(data = output_result_2)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

Iteration #3
output_3 <- result_3$output
output_t_3 <- result_3$output_t
output_3
gg <- ggplot(data = output_3)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

first_training_sample <- training.sampled_3[1:200,]
ggplot(first_training_sample) + geom_bar(aes(subclass))

class_distribution <- first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

testing_result_3 <- result$testing_result
#testing_result
gg <- ggplot(data = output_t_3)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

output_t_aux_3 <- output_t_3
names(output_t_aux_3) <- c('data_count_t','metric_t')
output_result_3 <- cbind(output_3,output_t_aux_3)
gg <- ggplot(data = output_result_3)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

Iteration #4
output_4 <- result_4$output
output_t_4 <- result_4$output_t
output_4
gg <- ggplot(data = output_4)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

first_training_sample <- training.sampled_4[1:200,]
ggplot(first_training_sample) + geom_bar(aes(subclass))

class_distribution <- first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

testing_result_4 <- result$testing_result
#testing_result
gg <- ggplot(data = output_t_4)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

output_t_aux_4 <- output_t_4
names(output_t_aux_4) <- c('data_count_t','metric_t')
output_result_4 <- cbind(output_4,output_t_aux_4)
gg <- ggplot(data = output_result_4)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

Iteration #5
output_5 <- result_5$output
output_t_5 <- result_5$output_t
output_5
gg <- ggplot(data = output_5)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

first_training_sample <- training.sampled_5[1:200,]
ggplot(first_training_sample) + geom_bar(aes(subclass))

class_distribution <- first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

testing_result_5 <- result$testing_result
#testing_result
gg <- ggplot(data = output_t_5)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

output_t_aux_5 <- output_t_5
names(output_t_aux_5) <- c('data_count_t','metric_t')
output_result_5 <- cbind(output_5,output_t_aux_5)
gg <- ggplot(data = output_result_5)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

Data training partitions: cold start study (simple Random Forest)
Iteration #1
rf_output_1 <- rf_result_1$output
rf_output_t_1 <- rf_result_1$output_t
rf_output_1
gg <- ggplot(data = rf_output_1)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

rf_first_training_sample <- rf_training.sampled_1[1:200,]
ggplot(rf_first_training_sample) + geom_bar(aes(subclass))

rf_class_distribution <- rf_first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(rf_first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

#rf_testing_result_1 <- rf_result_1$testing_result
#testing_result
gg <- ggplot(data = rf_output_t_1)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

rf_output_t_aux_1 <- rf_output_t_1
names(rf_output_t_aux_1) <- c('data_count_t','metric_t')
rf_output_result_1 <- cbind(rf_output_1,rf_output_t_aux_1)
gg <- ggplot(data = rf_output_result_1)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

Iteration #2
rf_output_2 <- rf_result_2$output
rf_output_t_2 <- rf_result_2$output_t
rf_output_2
gg <- ggplot(data = rf_output_2)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

rf_first_training_sample <- rf_training.sampled_2[1:200,]
ggplot(rf_first_training_sample) + geom_bar(aes(subclass))

rf_class_distribution <- rf_first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(rf_first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

#rf_testing_result_2 <- rf_result_2$testing_result
#testing_result
gg <- ggplot(data = rf_output_t_2)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

rf_output_t_aux_2 <- rf_output_t_2
names(rf_output_t_aux_2) <- c('data_count_t','metric_t')
rf_output_result_2 <- cbind(rf_output_2,rf_output_t_aux_2)
gg <- ggplot(data = rf_output_result_2)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

Iteration #3
rf_output_3 <- rf_result_3$output
rf_output_t_3 <- rf_result_3$output_t
rf_output_3
gg <- ggplot(data = rf_output_3)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

rf_first_training_sample <- rf_training.sampled_3[1:200,]
ggplot(rf_first_training_sample) + geom_bar(aes(subclass))

rf_class_distribution <- rf_first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(rf_first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

#rf_testing_result_2 <- rf_result_2$testing_result
#testing_result
gg <- ggplot(data = rf_output_t_3)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

rf_output_t_aux_3 <- rf_output_t_3
names(rf_output_t_aux_3) <- c('data_count_t','metric_t')
rf_output_result_3 <- cbind(rf_output_3,rf_output_t_aux_3)
gg <- ggplot(data = rf_output_result_3)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

Iteration #4
rf_output_4 <- rf_result_4$output
rf_output_t_4 <- rf_result_4$output_t
rf_output_4
gg <- ggplot(data = rf_output_4)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

rf_first_training_sample <- rf_training.sampled_4[1:200,]
ggplot(rf_first_training_sample) + geom_bar(aes(subclass))

rf_class_distribution <- rf_first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(rf_first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

#rf_testing_result_2 <- rf_result_2$testing_result
#testing_result
gg <- ggplot(data = rf_output_t_4)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

rf_output_t_aux_4 <- rf_output_t_4
names(rf_output_t_aux_4) <- c('data_count_t','metric_t')
rf_output_result_4 <- cbind(rf_output_4,rf_output_t_aux_4)
gg <- ggplot(data = rf_output_result_4)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

Iteration #5
rf_output_5 <- rf_result_5$output
rf_output_t_5 <- rf_result_5$output_t
rf_output_5
gg <- ggplot(data = rf_output_5)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

rf_first_training_sample <- rf_training.sampled_5[1:200,]
ggplot(rf_first_training_sample) + geom_bar(aes(subclass))

rf_class_distribution <- rf_first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(rf_first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

#rf_testing_result_2 <- rf_result_2$testing_result
#testing_result
gg <- ggplot(data = rf_output_t_5)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

rf_output_t_aux_5 <- rf_output_t_5
names(rf_output_t_aux_5) <- c('data_count_t','metric_t')
rf_output_result_5 <- cbind(rf_output_5,rf_output_t_aux_5)
gg <- ggplot(data = rf_output_result_5)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="F1 Score",
color=NULL)

Studies Samples
first_training_sample <- training.sampled[1:200,]
first_training_sample
ggplot(first_training_sample) + geom_bar(aes(subclass))
class_distribution <- first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))
part 2
set.seed(206)
library(doParallel)
cl <- makeCluster(2)
registerDoParallel(cl)
size_training <- nrow(training)
split_size_training = size_training / 200
count_random <- foreach(i=1:split_size_training) %dopar% {
200 * i
}
training.sampled <- training[sample(size_training, size_training), ]
metric <- foreach(i=1:split_size_training) %do% {
#library(caret)
count <- 200 * i
aux_training_set <- training.sampled[c(1:count), ]#training[sample(size_training, count), ]
clusters <- kmeans(aux_training_set[,-c(11,12,13,14)],3,nstart = 25)
aux_training_set_cluster <- cbind(aux_training_set, cluster = clusters$cluster)
result_vector <- numeric(nrow(testing))
for (j in c(1:3)){
cluster_data <- filter(aux_training_set_cluster, cluster == j)
new_rfFit <- train(class ~ sp+wp+wnp+snp+ds+dm+dl+ss+sm+sl,
data = cluster_data,
metric="ROC",
method = "rf",
trControl = ctrl_fast)
predsrfprobs <- predict(new_rfFit,testing,type='prob')
for (k in c(1:length(result_vector))){
if(predsrfprobs$Botnet[k] > 0.5){
result_vector[k] <- result_vector[k] + 1
}
else{
result_vector[k] <- result_vector[k] - 1
}
}
}
a = ifelse(result_vector > 0,'Botnet','Normal')
cm <- confusionMatrix(a,testing$class)
metric <- cm$byClass['F1']#cm$overall[1]
metric
}
output <- do.call(rbind, Map(data.frame, data_count=count_random, metric=metric))
output
gg <- ggplot(data = output)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') +
labs(title="Random Forest through data training size",
#subtitle="Drawn from Long Data format",
caption="Source: CTU-13",
y="Accuracy",
color=NULL)
cluster_data
Test with only one
set.seed(226)
size_training <- nrow(training)
training.sampled <- training[sample(size_training, size_training), ]
aux_training_set <- training.sampled[c(1:200), ]#training[sample(size_training, 200), ]
clusters <- kmeans(aux_training_set[,-c(11,12,13,14)],3,nstart = 25)
aux_training_set_cluster <- cbind(aux_training_set, cluster = clusters$cluster)
result_vector <- numeric(nrow(testing))
result_vector_trainning <- numeric(nrow(aux_training_set))
for (j in c(1:3)){
cluster_data <- aux_training_set_cluster %>% filter(cluster == j)
new_rfFit <- train(subclass ~ sp+wp+wnp+snp+ds+dm+dl+ss+sm+sl,
data = cluster_data,
metric="ROC",
method = "rf",
trControl = ctrl_fast)
predsrfprobs <- predict(new_rfFit,testing,type='prob')
for (k in c(1:length(result_vector))){
if(predsrfprobs$botnet[k] > 0.5){
result_vector[k] <- result_vector[k] + 1
}
else{
result_vector[k] <- result_vector[k] - 1
}
}
#Trainning predict
predsrfprobs_t <- predict(new_rfFit,aux_training_set,type='prob')
for (k in c(1:length(result_vector_trainning))){
if(predsrfprobs_t$botnet[k] > 0.5){
result_vector_trainning[k] <- result_vector_trainning[k] + 1
}
else{
result_vector_trainning[k] <- result_vector_trainning[k] - 1
}
}
}
a = ifelse(result_vector > 0,'botnet','normal')
b <- ifelse(result_vector_trainning > 0,'botnet','normal')
cm <- confusionMatrix(a,testing$subclass)
metric <- cm$byClass['F1']#cm$overall[1]
metric
cm_t <- confusionMatrix(b,aux_training_set$subclass)
metric_t <- cm_t$byClass['F1']
metric_t
Sample examples
set.seed(556)
a = c(1,2,3,4,5,6,7,8,9)
r <- sample(9,3)
a[r]
r2 <- sample(9,3)
a[r2]
#testing_result
testing_result.bkp <- testing_result
testing_result
names_aux <- foreach(i=1:(nrow(training)/200)) %do% {
iteration <- 200 * i
paste('size_',toString(iteration),sep = "")
}
testing_result_names <- unlist(names_aux, use.names=FALSE)
testing_result <- testing_result[,c(-1)]
names(testing_result) <- testing_result_names
testing_result
testing_aux <- cbind(testing,testing_result)
testing_aux.bkp2 <- testing_aux
#write.table(testing_aux,file="testing_cluster_result.txt",sep="|", row.names = F)
testing_aux
sums <- rowSums(testing_aux[,-c(1:14)])
sums
testing_aux[,-c(1:14)]
testing_aux <- cbind(testing_aux,sums)
testing_aux
testing_aux_result <- testing_aux %>% group_by(class) %>% summarise(n = n(), sums = sum(sums)) %>% arrange(desc(sums))
testing_aux_result
graph_testing_result <- ggplot(testing_aux_result[-c(1,nrow(testing_aux_result)),])
graph_testing_result + geom_point(aes(class,sums)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))
feature_vectors_cleaned
library(gridExtra)
pdf("data_output.pdf", height=11, width=8.5)
grid.table(feature_vectors_cleaned[1:20,])
dev.off()
testing_result.bkp
testing_aux.bkp2
testing_aux_result
rusty_data_result <- testing_aux.bkp2
rusty_data_result_short <- rusty_data_result[,-c(1:11,14)]
rusty_data_result_short[,-c(1,2)]
rusty_data_result_short$pos <- rowSums(rusty_data_result_short[,-c(1,2)] > 0)
rusty_data_result_short$neg <- rowSums(rusty_data_result_short[,-c(1,2)] < 0)
rusty_data_result_short_cleaned <- rusty_data_result_short[,c(1,2,46,47)]
rusty_data_result_short_cleaned
rusty_data_result_short_cleaned_result <- rusty_data_result_short_cleaned %>% mutate(good = ifelse(subclass == 'normal',neg,pos))
rusty_data_result_short_cleaned_result <- rusty_data_result_short_cleaned_result %>% mutate(bad = ifelse(subclass == 'normal',pos,neg))
rusty_data_result_short_cleaned_result %>% group_by(port) %>% summarise(n=n(),good = sum(good),bad = sum(bad)) %>% arrange(desc(n))
data_botnet_port <- rusty_data_result_short_cleaned_result %>% filter(subclass == 'botnet')
data_normal_port <- rusty_data_result_short_cleaned_result %>% filter(subclass == 'normal')
data_botnet_port_result <- data_botnet_port %>% group_by(port) %>% summarise(n=n(),good = sum(good),bad = sum(bad)) %>% arrange(desc(n))
data_normal_port_result <- data_normal_port %>% group_by(port) %>% summarise(n=n(),good = sum(good),bad = sum(bad)) %>% arrange(desc(n))
data_botnet_port_result
data_normal_port_result
ggplot(data = data_botnet_port_result) +
geom_bar(mapping = aes(x = port, fill = clarity))
#write.table(data_botnet_port_result,file="data_botnet_port.txt",sep="|", row.names = F)
library(reshape2)
data <- data_botnet_port_result
data$port <- as.factor(data$port)
melt(data[,c(1,3,4)])
ggplot(melt(data[,c(1,3,4)]))+
geom_col(aes(x=port,y=value,fill=variable))+
#theme_bw()+
theme(axis.text.x = element_text(angle = 45, hjust = 1))
LS0tCnRpdGxlOiAiQ0FJJ3MgZXhwZXJpbWVudHMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyBMaWJyYXJ5IEVudmlyb25tZW50CmBgYHtyfQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkodGlkeXZlcnNlKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHN0cmluZ3IpKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoSVNMUikpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShjYXJldCkpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShkb01DKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHBsb3RseSkpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShzdHJpbmdyKSkKcmVnaXN0ZXJEb01DKGNvcmVzPTQpCmBgYAoKIyMjIExvYWQgYW5kIHByb2Nlc3NpbmcgZGF0YSBjdHUxMyBjbGVhbmVkCmBgYHtyfQpteURhdGFfY2xlYW5lZCA8LSByZWFkLmNzdignL2hvbWUvamd1ZXJyYS9kYXRhc2V0cy9jdHUxMy5sYWJlbGVkLmNsZWFuZWQnLCBzdHJpbmdzQXNGYWN0b3JzID0gRiwgc2VwID0gJ3wnKQpteURhdGFfY2xlYW5lZC5ia3AgPSBteURhdGFfY2xlYW5lZApteURhdGFfY2xlYW5lZAoKI1BlcmlvZGljaXR5Cm15RGF0YV9jbGVhbmVkID0gbXlEYXRhX2NsZWFuZWQgJT4lIG11dGF0ZShzdHJvbmdfcCA9IHN0cl9jb3VudChTdGF0ZSwnW2EtaV0nKSkKbXlEYXRhX2NsZWFuZWQgPSBteURhdGFfY2xlYW5lZCAlPiUgbXV0YXRlKHdlYWtfcCA9IHN0cl9jb3VudChTdGF0ZSwnW0EtSV0nKSkKbXlEYXRhX2NsZWFuZWQgPSBteURhdGFfY2xlYW5lZCAlPiUgbXV0YXRlKHdlYWtfbnAgPSBzdHJfY291bnQoU3RhdGUsJ1tyLXpdJykpCm15RGF0YV9jbGVhbmVkID0gbXlEYXRhX2NsZWFuZWQgJT4lIG11dGF0ZShzdHJvbmdfbnAgPSBzdHJfY291bnQoU3RhdGUsJ1tSLVpdJykpCiNEdXJhdGlvbgpteURhdGFfY2xlYW5lZCA9IG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoZHVyYXRpb25fcyA9IHN0cl9jb3VudChTdGF0ZSwnKGF8QXxyfFJ8MXxkfER8dXxVfDR8Z3xHfHh8WHw3KScpKQpteURhdGFfY2xlYW5lZCA9IG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoZHVyYXRpb25fbSA9IHN0cl9jb3VudChTdGF0ZSwnKGJ8QnxzfFN8MnxlfEV8dnxWfDV8aHxIfHl8WXw4KScpKQpteURhdGFfY2xlYW5lZCA9IG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoZHVyYXRpb25fbCA9IHN0cl9jb3VudChTdGF0ZSwnKGN8Q3x0fFR8M3xmfEZ8d3xXfDZ8aXxJfHp8Wnw5KScpKQojU2l6ZQpteURhdGFfY2xlYW5lZCA9IG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoc2l6ZV9zID0gc3RyX2NvdW50KFN0YXRlLCdbYS1jXScpICsgc3RyX2NvdW50KFN0YXRlLCdbQS1DXScpICsgc3RyX2NvdW50KFN0YXRlLCdbci10XScpICsgc3RyX2NvdW50KFN0YXRlLCdbUi1UXScpICsgc3RyX2NvdW50KFN0YXRlLCdbMS0zXScpKQpteURhdGFfY2xlYW5lZCA9IG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoc2l6ZV9tID0gc3RyX2NvdW50KFN0YXRlLCdbZC1mXScpICsgc3RyX2NvdW50KFN0YXRlLCdbRC1GXScpICsgc3RyX2NvdW50KFN0YXRlLCdbdS13XScpICsgc3RyX2NvdW50KFN0YXRlLCdbVS1XXScpICsgc3RyX2NvdW50KFN0YXRlLCdbNC02XScpKQpteURhdGFfY2xlYW5lZCA9IG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoc2l6ZV9sID0gc3RyX2NvdW50KFN0YXRlLCdbZy1pXScpICsgc3RyX2NvdW50KFN0YXRlLCdbRy1JXScpICsgc3RyX2NvdW50KFN0YXRlLCdbeC16XScpICsgc3RyX2NvdW50KFN0YXRlLCdbWC1aXScpICsgc3RyX2NvdW50KFN0YXRlLCdbNy05XScpKQoKI1BlcmlvZGljaXR5ICUKbXlEYXRhX2NsZWFuZWQgPC0gbXlEYXRhX2NsZWFuZWQgJT4lIG11dGF0ZShzdHJvbmdfcCA9IChzdHJvbmdfcCAvIG1vZGVsc2l6ZSkpCm15RGF0YV9jbGVhbmVkIDwtIG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUod2Vha19wID0gKHdlYWtfcCAvIG1vZGVsc2l6ZSkpCm15RGF0YV9jbGVhbmVkIDwtIG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoc3Ryb25nX25wID0gKHN0cm9uZ19ucCAvIG1vZGVsc2l6ZSkpCm15RGF0YV9jbGVhbmVkIDwtIG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUod2Vha19ucCA9ICh3ZWFrX25wIC8gbW9kZWxzaXplKSkKI0R1cmF0aW9uICUKbXlEYXRhX2NsZWFuZWQgPC0gbXlEYXRhX2NsZWFuZWQgJT4lIG11dGF0ZShkdXJhdGlvbl9zID0gKGR1cmF0aW9uX3MgLyBtb2RlbHNpemUpKQpteURhdGFfY2xlYW5lZCA8LSBteURhdGFfY2xlYW5lZCAlPiUgbXV0YXRlKGR1cmF0aW9uX20gPSAoZHVyYXRpb25fbSAvIG1vZGVsc2l6ZSkpCm15RGF0YV9jbGVhbmVkIDwtIG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoZHVyYXRpb25fbCA9IChkdXJhdGlvbl9sIC8gbW9kZWxzaXplKSkKI1NpemUgJQpteURhdGFfY2xlYW5lZCA8LSBteURhdGFfY2xlYW5lZCAlPiUgbXV0YXRlKHNpemVfcyA9IChzaXplX3MgLyBtb2RlbHNpemUpKQpteURhdGFfY2xlYW5lZCA8LSBteURhdGFfY2xlYW5lZCAlPiUgbXV0YXRlKHNpemVfbSA9IChzaXplX20gLyBtb2RlbHNpemUpKQpteURhdGFfY2xlYW5lZCA8LSBteURhdGFfY2xlYW5lZCAlPiUgbXV0YXRlKHNpemVfbCA9IChzaXplX2wgLyBtb2RlbHNpemUpKQoKI01ha2luZyBmZWF0dXJlIHZlY3RvcnMKZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWQgPSBteURhdGFfY2xlYW5lZFssYygnc3Ryb25nX3AnLCd3ZWFrX3AnLCd3ZWFrX25wJywnc3Ryb25nX25wJywnZHVyYXRpb25fcycsJ2R1cmF0aW9uX20nLCdkdXJhdGlvbl9sJywnc2l6ZV9zJywnc2l6ZV9tJywnc2l6ZV9sJywnbW9kZWxzaXplJywnbGFiZWwnLCdjbGFzcycsJ3BvcnQnLCdwcm90bycpXQpuYW1lcyhmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZCkgPSBjKCJzcCIsIndwIiwid25wIiwic25wIiwiZHMiLCJkbSIsImRsIiwic3MiLCJzbSIsInNsIiwibW9kZWxzaXplIiwiY2xhc3MiLCJzdWJjbGFzcyIsInBvcnQiLCJwcm90byIpCmZlYXR1cmVfdmVjdG9yc19jbGVhbmVkJGNsYXNzID0gZmFjdG9yKGZlYXR1cmVfdmVjdG9yc19jbGVhbmVkJGNsYXNzKQpmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZCRzdWJjbGFzcyA9IGZhY3RvcihmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZCRzdWJjbGFzcykKZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWQkcHJvdG8gPSBmYWN0b3IoZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWQkcHJvdG8pCgpmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZAoKYGBgCgojIyMgUmVtb3ZpbmcgZXhjZXNpdmUgQm90bmV0IGFuZCBOb3JtYWwgY2xhc3MoTWFraW5nIHRoZSBkYXRhc2V0IG1vcmUgZXF1aXRhYmxlKQpgYGB7cn0KZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWQuYmtwIDwtIGZlYXR1cmVfdmVjdG9yc19jbGVhbmVkCmZlYXR1cmVfdmVjdG9yc19jbGVhbmVkICU+JSBncm91cF9ieShjbGFzcykgJT4lIHN1bW1hcmlzZShuPW4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWRfYXV4X2JvdG5ldCA8LSBmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZCAlPiUgZmlsdGVyKGNsYXNzID09ICdCb3RuZXQtVENQLVNNVFAtQXR0ZW1wdC1TUEFNJykKZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWRfYXV4X25vcm1hbCA8LSBmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZCAlPiUgZmlsdGVyKGNsYXNzID09ICdOb3JtYWwtVENQLUhUVFAnKQpmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZF9hdXhfYm90bmV0CmZlYXR1cmVfdmVjdG9yc19jbGVhbmVkX2F1eF9ub3JtYWwKCmZlYXR1cmVfdmVjdG9yc19jbGVhbmVkX2F1eF9yZXN0IDwtIGZlYXR1cmVfdmVjdG9yc19jbGVhbmVkICU+JSBmaWx0ZXIoY2xhc3MgIT0gJ0JvdG5ldC1UQ1AtU01UUC1BdHRlbXB0LVNQQU0nKSAlPiUgZmlsdGVyKGNsYXNzICE9ICdOb3JtYWwtVENQLUhUVFAnKQpmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZF9hdXhfcmVzdCAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2Uobj1uKCkpICU+JSBhcnJhbmdlKGRlc2MobikpCmF1eDEgPC0gcmJpbmQoZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWRfYXV4X2JvdG5ldFsxOjUwMCxdLGZlYXR1cmVfdmVjdG9yc19jbGVhbmVkX2F1eF9ub3JtYWxbMTo1MDAsXSkKYXV4MSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2Uobj1uKCkpICU+JSBhcnJhbmdlKGRlc2MobikpCmF1eCA8LSByYmluZChmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZF9hdXhfcmVzdCxhdXgxKQphdXggJT4lIGdyb3VwX2J5KGNsYXNzKSAlPiUgc3VtbWFyaXNlKG49bigpKSAlPiUgYXJyYW5nZShkZXNjKG4pKQpmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZCA8LSBhdXgKYGBgCgojIyMgQ3JlYXRlIHRyYWluaW5nIHNldCBhbmQgdGVzdHNldApgYGB7cn0Kc2V0LnNlZWQoMjEyKQp0cmFpbkluZGV4IDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWQkc3ViY2xhc3MsIHA9MC43MCwgbGlzdD1GQUxTRSkKZGF0YV90cmFpbmluZyA8LSBmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZFsgdHJhaW5JbmRleCxdCmRhdGFfdGVzdGluZyA8LSBmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZFstdHJhaW5JbmRleCxdCgojZGF0YV90cmFpbiA9IGRhdGFfdHJhaW4gJT4lIGZpbHRlcihsZW5ndGg+NSkKdHJhaW4gPC0gdXBTYW1wbGUoeCA9IGRhdGFfdHJhaW5pbmcsICB5ID0gZGF0YV90cmFpbmluZyRzdWJjbGFzcywgeW5hbWU9ImNsYXNzIikKCnRyYWluaW5nIDwtIHRyYWluWywtYygxMSwxNildCnRlc3RpbmcgPC0gZGF0YV90ZXN0aW5nWywtYygxMSldCnRyYWluaW5nCnRlc3RpbmcKCm5yb3codHJhaW5pbmcpCm5yb3coZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWQpCgpgYGAKCiMjIyBUcmFpbmluZyBjb25maWd1cmF0aW9uCmBgYHtyfQpjdHJsX2Zhc3QgPC0gdHJhaW5Db250cm9sKG1ldGhvZD0iY3YiLCAKICAgICAgICAgICAgICAgICAgICAgcmVwZWF0cz0yLAogICAgICAgICAgICAgICAgICAgICBudW1iZXI9MTAsIAogICAgICAgICAgICAgICAgICAgICBzdW1tYXJ5RnVuY3Rpb249dHdvQ2xhc3NTdW1tYXJ5LAogICAgICAgICAgICAgICAgICAgICB2ZXJib3NlSXRlcj1ULAogICAgICAgICAgICAgICAgICAgICBjbGFzc1Byb2JzPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgIGFsbG93UGFyYWxsZWwgPSBUUlVFKSAgCmBgYAoKIyMjIEV4cGVyaW1lbnQgMQojIyBDcmVhdGlvbiBvZiBjbHVzdGVyIGFuZCBrIHBhcmFtZXRlcnMgYW5hbHlzaXMKYGBge3J9CmxpYnJhcnkoZmFjdG9leHRyYSkKbGlicmFyeShjbHVzdGVyKQpsaWJyYXJ5KE5iQ2x1c3QpCmZlYXR1cmVfdmVjdG9yX3RyYWluaW5nID0gdHJhaW5pbmdbLC1jKDExLDEyLDEzLDE0KV0KIyBLLW1lYW5zIGNsdXN0ZXJpbmcKc2V0LnNlZWQoMzIxKQoja20ucmVzIDwtIGttZWFucyhmZWF0dXJlX3ZlY3Rvcl90cmFpbmluZywgMywgbnN0YXJ0ID0gMjUpCmttLnJlcyA8LSBrbWVhbnMoZmVhdHVyZV92ZWN0b3JfdHJhaW5pbmcsIDcsIG5zdGFydCA9IDI1KQojIGstbWVhbnMgZ3JvdXAgbnVtYmVyIG9mIGVhY2ggb2JzZXJ2YXRpb24Ka20ucmVzJGNsdXN0ZXIKCiMgVmlzdWFsaXplIGstbWVhbnMgY2x1c3RlcnMKZnZpel9jbHVzdGVyKGttLnJlcywgZGF0YSA9IGZlYXR1cmVfdmVjdG9yX3RyYWluaW5nLCBnZW9tID0gInBvaW50IiwKICAgICAgICAgICAgIHN0YW5kID0gRkFMU0UsIGVsbGlwc2UudHlwZSA9ICJub3JtIikKYGBgCiMjIyBFbGJvdyBhbmFseXNpcwpgYGB7cn0Kc2V0LnNlZWQoMzIxKQojIENvbXB1dGUgYW5kIHBsb3Qgd3NzIGZvciBrID0gMiB0byBrID0gMTUKay5tYXggPC0gMTUgIyBNYXhpbWFsIG51bWJlciBvZiBjbHVzdGVycwpkYXRhIDwtIGZlYXR1cmVfdmVjdG9yX3RyYWluaW5nCndzcyA8LSBzYXBwbHkoMTprLm1heCwgCiAgICAgICAgZnVuY3Rpb24oayl7a21lYW5zKGRhdGEsIGssIG5zdGFydD0xMCApJHRvdC53aXRoaW5zc30pCnBsb3QoMTprLm1heCwgd3NzLAogICAgICAgdHlwZT0iYiIsIHBjaCA9IDE5LCBmcmFtZSA9IEZBTFNFLCAKICAgICAgIHhsYWI9Ik51bWJlciBvZiBjbHVzdGVycyBLIiwKICAgICAgIHlsYWI9IlRvdGFsIHdpdGhpbi1jbHVzdGVycyBzdW0gb2Ygc3F1YXJlcyIpCmFibGluZSh2ID0gMywgbHR5ID0yKQpgYGAKIyMgU2lsaG91ZXR0ZSBhbmFseXNpcwpgYGB7cn0Kc2V0LnNlZWQoMzIyKQprLm1heCA8LSAxMApkYXRhIDwtIGZlYXR1cmVfdmVjdG9yX3RyYWluaW5nCm5yb3coZGF0YSkKc2lsIDwtIHJlcCgwLCBrLm1heCkKIyBDb21wdXRlIHRoZSBhdmVyYWdlIHNpbGhvdWV0dGUgd2lkdGggZm9yIAojIGsgPSAyIHRvIGsgPSAxNQoKZm9yKGkgaW4gMjprLm1heCl7CiAga20ucmVzIDwtIGttZWFucyhkYXRhLCBjZW50ZXJzID0gaSwgbnN0YXJ0ID0gMjUpCiAgc3MgPC0gc2lsaG91ZXR0ZShrbS5yZXMkY2x1c3RlciwgZGlzdChkYXRhKSkKICBzaWxbaV0gPC0gbWVhbihzc1ssIDNdKQp9CiMgUGxvdCB0aGUgIGF2ZXJhZ2Ugc2lsaG91ZXR0ZSB3aWR0aApwbG90KDE6ay5tYXgsIHNpbCwgdHlwZSA9ICJiIiwgcGNoID0gMTksIAogICAgIGZyYW1lID0gRkFMU0UsIHhsYWIgPSAiTnVtYmVyIG9mIGNsdXN0ZXJzIGsiKQphYmxpbmUodiA9IHdoaWNoLm1heChzaWwpLCBsdHkgPSAyKQoKYGBgCiMjIyBVc2VmdWwgZnVuY3Rpb25zCmBgYHtyfQpjb2xkX3N0YXJ0X2RhdGEgPC0gZnVuY3Rpb24odHJhaW5pbmcuc2FtcGxlZCx0ZXN0aW5nLHNldHRpbmdzKXsKICBsaWJyYXJ5KGRvUGFyYWxsZWwpCiAgY2wgPC0gbWFrZUNsdXN0ZXIoMikKICByZWdpc3RlckRvUGFyYWxsZWwoY2wpCiAgc2l6ZV90cmFpbmluZyA8LSBucm93KHRyYWluaW5nLnNhbXBsZWQpCiAgc3BsaXRfc2l6ZV90cmFpbmluZyA9IHNpemVfdHJhaW5pbmcgLyAyMDAKICB0ZXN0aW5nX3Jlc3VsdCA9IGRhdGEuZnJhbWUobnVtZXJpYyhucm93KHRlc3RpbmcpKSkKICAKICBjb3VudF9yYW5kb20gPC0gZm9yZWFjaChpPTE6c3BsaXRfc2l6ZV90cmFpbmluZykgJWRvcGFyJSB7CiAgICAyMDAgKiBpCiAgfQogIG1ldHJpYyA8LSBudW1lcmljKHNwbGl0X3NpemVfdHJhaW5pbmcpCiAgbWV0cmljX3QgPC0gbnVtZXJpYyhzcGxpdF9zaXplX3RyYWluaW5nKQogICNtZXRyaWMgPC0gZm9yZWFjaChpPTE6c3BsaXRfc2l6ZV90cmFpbmluZykgJWRvJSB7CiAgZm9yKGkgaW4gYygxOnNwbGl0X3NpemVfdHJhaW5pbmcpKXsKICAgICNsaWJyYXJ5KGNhcmV0KQogICAgI2xpYnJhcnkoZHBseXIpCiAgICBjb3VudCA8LSAyMDAgKiBpCiAgICBhdXhfdHJhaW5pbmdfc2V0IDwtIHRyYWluaW5nLnNhbXBsZWRbYygxOmNvdW50KSwgXSN0cmFpbmluZ1tzYW1wbGUoc2l6ZV90cmFpbmluZywgY291bnQpLCBdCiAgICBjbHVzdGVycyA8LSBrbWVhbnMoYXV4X3RyYWluaW5nX3NldFssLWMoMTEsMTIsMTMsMTQpXSwzLG5zdGFydCA9IDI1KQogICAgYXV4X3RyYWluaW5nX3NldF9jbHVzdGVyIDwtIGNiaW5kKGF1eF90cmFpbmluZ19zZXQsIGNsdXN0ZXIgPSBjbHVzdGVycyRjbHVzdGVyKQogICAgcmVzdWx0X3ZlY3RvciA8LSBudW1lcmljKG5yb3codGVzdGluZykpCiAgICByZXN1bHRfdmVjdG9yX3RyYWlubmluZyA8LSBudW1lcmljKG5yb3coYXV4X3RyYWluaW5nX3NldCkpCiAgICAKICAgIGZvciAoaiBpbiBjKDE6MykpewogICAgICBjbHVzdGVyX2RhdGEgPC0gZHBseXI6OmZpbHRlcihhdXhfdHJhaW5pbmdfc2V0X2NsdXN0ZXIsIGNsdXN0ZXIgPT0gaikKICAgICAgbmV3X3JmRml0IDwtIHRyYWluKHN1YmNsYXNzIH4gc3Ard3Ard25wK3NucCtkcytkbStkbCtzcytzbStzbCwKICAgICAgICAgICAgICAgICBkYXRhID0gY2x1c3Rlcl9kYXRhLAogICAgICAgICAgICAgICAgIG1ldHJpYz0iUk9DIiwKICAgICAgICAgICAgICAgICBtZXRob2QgPSAicmYiLAogICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IHNldHRpbmdzKQogICAgICAjVGVzdGluZyBwcmVkaWN0CiAgICAgIHByZWRzcmZwcm9icyA8LSBwcmVkaWN0KG5ld19yZkZpdCx0ZXN0aW5nLHR5cGU9J3Byb2InKQogICAgICAKICAgICAgZm9yIChrIGluIGMoMTpsZW5ndGgocmVzdWx0X3ZlY3RvcikpKXsKICAgICAgICBpZihwcmVkc3JmcHJvYnMkYm90bmV0W2tdID4gMC41KXsKICAgICAgICAgIHJlc3VsdF92ZWN0b3Jba10gPC0gcmVzdWx0X3ZlY3RvcltrXSArIDEKICAgICAgICB9CiAgICAgICAgZWxzZXsKICAgICAgICAgIHJlc3VsdF92ZWN0b3Jba10gPC0gcmVzdWx0X3ZlY3RvcltrXSAtIDEKICAgICAgICB9CiAgICAgIH0KICAgICAgCiAgICAgICNUcmFpbm5pbmcgcHJlZGljdAogICAgICBwcmVkc3JmcHJvYnNfdCA8LSBwcmVkaWN0KG5ld19yZkZpdCxhdXhfdHJhaW5pbmdfc2V0LHR5cGU9J3Byb2InKQogICAgICBmb3IgKGsgaW4gYygxOmxlbmd0aChyZXN1bHRfdmVjdG9yX3RyYWlubmluZykpKXsKICAgICAgICBpZihwcmVkc3JmcHJvYnNfdCRib3RuZXRba10gPiAwLjUpewogICAgICAgICAgcmVzdWx0X3ZlY3Rvcl90cmFpbm5pbmdba10gPC0gcmVzdWx0X3ZlY3Rvcl90cmFpbm5pbmdba10gKyAxCiAgICAgICAgfQogICAgICAgIGVsc2V7CiAgICAgICAgICByZXN1bHRfdmVjdG9yX3RyYWlubmluZ1trXSA8LSByZXN1bHRfdmVjdG9yX3RyYWlubmluZ1trXSAtIDEKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIGEgPSBpZmVsc2UocmVzdWx0X3ZlY3RvciA+IDAsJ2JvdG5ldCcsJ25vcm1hbCcpCiAgICBiIDwtIGlmZWxzZShyZXN1bHRfdmVjdG9yX3RyYWlubmluZyA+IDAsJ2JvdG5ldCcsJ25vcm1hbCcpCiAgICB0ZXN0aW5nX3Jlc3VsdCA8LSBjYmluZCh0ZXN0aW5nX3Jlc3VsdCwncmVzdWx0JyA9IHJlc3VsdF92ZWN0b3IpCiAgICBjbSA8LSBjb25mdXNpb25NYXRyaXgoYSx0ZXN0aW5nJHN1YmNsYXNzKQogICAgbWV0cmljW2ldIDwtIGNtJGJ5Q2xhc3NbJ0YxJ10jY20kb3ZlcmFsbFsxXQogICAgCiAgICBjbV90IDwtIGNvbmZ1c2lvbk1hdHJpeChiLGF1eF90cmFpbmluZ19zZXQkc3ViY2xhc3MpCiAgICBtZXRyaWNfdFtpXSA8LSBjbV90JGJ5Q2xhc3NbJ0YxJ10KICAgICNsaXN0KCdtZXRyaWMnID0gbWV0cmljLCAnbWV0cmljX3QnID0gbWV0cmljX3QpCiAgfQogIG91dHB1dCA8LSBkby5jYWxsKHJiaW5kLCBNYXAoZGF0YS5mcmFtZSwgZGF0YV9jb3VudD1jb3VudF9yYW5kb20sIG1ldHJpYz1tZXRyaWMpKQogIG91dHB1dF90IDwtIGRvLmNhbGwocmJpbmQsIE1hcChkYXRhLmZyYW1lLCBkYXRhX2NvdW50PWNvdW50X3JhbmRvbSwgbWV0cmljPW1ldHJpY190KSkKICBsaXN0X3Jlc3VsdCA8LSBsaXN0KCdvdXRwdXQnID0gb3V0cHV0LCAnb3V0cHV0X3QnID0gb3V0cHV0X3QsICd0ZXN0aW5nX3Jlc3VsdCcgPSB0ZXN0aW5nX3Jlc3VsdCkKfQoKY29sZF9zdGFydF9kYXRhX29ubHlfcmYgPC0gZnVuY3Rpb24odHJhaW5pbmcuc2FtcGxlZCx0ZXN0aW5nLHNldHRpbmdzKXsKICBzaXplX3RyYWluaW5nIDwtIG5yb3codHJhaW5pbmcuc2FtcGxlZCkKICBzcGxpdF9zaXplX3RyYWluaW5nID0gc2l6ZV90cmFpbmluZyAvIDIwMAogIHRlc3RpbmdfcmVzdWx0ID0gZGF0YS5mcmFtZShudW1lcmljKG5yb3codGVzdGluZykpKQogIAogIGNvdW50X3JhbmRvbSA8LSBmb3JlYWNoKGk9MTpzcGxpdF9zaXplX3RyYWluaW5nKSAlZG9wYXIlIHsKICAgIDIwMCAqIGkKICB9CiAgbWV0cmljIDwtIG51bWVyaWMoc3BsaXRfc2l6ZV90cmFpbmluZykKICBtZXRyaWNfdCA8LSBudW1lcmljKHNwbGl0X3NpemVfdHJhaW5pbmcpCiAgI21ldHJpYyA8LSBmb3JlYWNoKGk9MTpzcGxpdF9zaXplX3RyYWluaW5nKSAlZG8lIHsKICBmb3IoaSBpbiBjKDE6c3BsaXRfc2l6ZV90cmFpbmluZykpewogICAgI2xpYnJhcnkoY2FyZXQpCiAgICAjbGlicmFyeShkcGx5cikKICAgIGNvdW50IDwtIDIwMCAqIGkKICAgIGF1eF90cmFpbmluZ19zZXQgPC0gdHJhaW5pbmcuc2FtcGxlZFtjKDE6Y291bnQpLCBdI3RyYWluaW5nW3NhbXBsZShzaXplX3RyYWluaW5nLCBjb3VudCksIF0KICAgIG5ld19yZkZpdCA8LSB0cmFpbihzdWJjbGFzcyB+IHNwK3dwK3ducCtzbnArZHMrZG0rZGwrc3Mrc20rc2wsCiAgICAgICAgICAgICAgICAgZGF0YSA9IGF1eF90cmFpbmluZ19zZXQsCiAgICAgICAgICAgICAgICAgbWV0cmljPSJST0MiLAogICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJyZiIsCiAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gc2V0dGluZ3MpCiAgICAjVGVzdGluZyBwcmVkaWN0CiAgICBwcmVkc3JmcHJvYnMgPC0gcHJlZGljdChuZXdfcmZGaXQsdGVzdGluZyx0eXBlPSdwcm9iJykKICAgIHByZWRzcmYgPC0gaWZlbHNlKHByZWRzcmZwcm9icyRib3RuZXQgPj0wLjUsJ2JvdG5ldCcsJ25vcm1hbCcpCiAgICBjbSA8LSBjb25mdXNpb25NYXRyaXgocHJlZHNyZix0ZXN0aW5nJHN1YmNsYXNzKQogICAgbWV0cmljW2ldIDwtIGNtJGJ5Q2xhc3NbJ0YxJ10KICAgIAogICAgCiAgICAjVHJhaW5uaW5nIHByZWRpY3QKICAgIHByZWRzcmZwcm9ic190IDwtIHByZWRpY3QobmV3X3JmRml0LGF1eF90cmFpbmluZ19zZXQsdHlwZT0ncHJvYicpCiAgICBwcmVkc3JmX3QgPC0gaWZlbHNlKHByZWRzcmZwcm9ic190JGJvdG5ldCA+PSAwLjUsJ2JvdG5ldCcsJ25vcm1hbCcpCiAgICBjbV90IDwtIGNvbmZ1c2lvbk1hdHJpeChwcmVkc3JmX3QsYXV4X3RyYWluaW5nX3NldCRzdWJjbGFzcykKICAgIG1ldHJpY190W2ldIDwtIGNtX3QkYnlDbGFzc1snRjEnXQogICAgCiAgfQogIG91dHB1dCA8LSBkby5jYWxsKHJiaW5kLCBNYXAoZGF0YS5mcmFtZSwgZGF0YV9jb3VudD1jb3VudF9yYW5kb20sIG1ldHJpYz1tZXRyaWMpKQogIG91dHB1dF90IDwtIGRvLmNhbGwocmJpbmQsIE1hcChkYXRhLmZyYW1lLCBkYXRhX2NvdW50PWNvdW50X3JhbmRvbSwgbWV0cmljPW1ldHJpY190KSkKICBsaXN0X3Jlc3VsdCA8LSBsaXN0KCdvdXRwdXQnID0gb3V0cHV0LCAnb3V0cHV0X3QnID0gb3V0cHV0X3QsICd0ZXN0aW5nX3Jlc3VsdCcgPSB0ZXN0aW5nX3Jlc3VsdCkKfQoKZ2VuZXJhdGVfZGF0YV9ub2lzeSA8LSBmdW5jdGlvbihkYXRhc2V0LCBwb3JjZW50KXsKICBsaXN0X2F1eCA8LSBzYW1wbGUobnJvdyhkYXRhc2V0KSAscG9yY2VudCkKICBub2lzeV9kYXRhX3NhbXBsZSA8LSBkYXRhc2V0W2xpc3RfYXV4LF0KICBub19ub2lzeV9kYXRhX3NhbXBsZSA8LSBkYXRhc2V0Wy1saXN0X2F1eCxdCiAgCiAgbm9pc3lfZGF0YV9zYW1wbGVfYiA8LSBub2lzeV9kYXRhX3NhbXBsZSAlPiUgZmlsdGVyKGNsYXNzID09ICdCb3RuZXQnKQogIG5vaXN5X2RhdGFfc2FtcGxlX24gPC0gbm9pc3lfZGF0YV9zYW1wbGUgJT4lIGZpbHRlcihjbGFzcyA9PSAnTm9ybWFsJykKICAKICBub2lzeV9kYXRhX3NhbXBsZV9iJGNsYXNzIDwtIGFzLmNoYXJhY3Rlcihub2lzeV9kYXRhX3NhbXBsZV9iJGNsYXNzKQogIG5vaXN5X2RhdGFfc2FtcGxlX2IkY2xhc3Nbbm9pc3lfZGF0YV9zYW1wbGVfYiRjbGFzcyA9PSAnQm90bmV0J10gPC0gJ05vcm1hbCcKICBub2lzeV9kYXRhX3NhbXBsZV9iJGNsYXNzIDwtIGFzLmZhY3Rvcihub2lzeV9kYXRhX3NhbXBsZV9iJGNsYXNzKQogIAogIG5vaXN5X2RhdGFfc2FtcGxlX24kY2xhc3MgPC0gYXMuY2hhcmFjdGVyKG5vaXN5X2RhdGFfc2FtcGxlX24kY2xhc3MpCiAgbm9pc3lfZGF0YV9zYW1wbGVfbiRjbGFzc1tub2lzeV9kYXRhX3NhbXBsZV9uJGNsYXNzID09ICdOb3JtYWwnXSA8LSAnQm90bmV0JwogIG5vaXN5X2RhdGFfc2FtcGxlX24kY2xhc3MgPC0gYXMuZmFjdG9yKG5vaXN5X2RhdGFfc2FtcGxlX24kY2xhc3MpCiAgCiAgbm9pc3lfZGF0YSA8LSByYmluZChub2lzeV9kYXRhX3NhbXBsZV9iLCBub2lzeV9kYXRhX3NhbXBsZV9uKQogIHRyYWluaW5nX25vaXN5IDwtIHJiaW5kKG5vX25vaXN5X2RhdGFfc2FtcGxlLG5vaXN5X2RhdGEpCiAgdHJhaW5pbmdfbm9pc3kgPC0gdHJhaW5pbmdfbm9pc3lbc2FtcGxlKG5yb3codHJhaW5pbmdfbm9pc3kpLG5yb3codHJhaW5pbmdfbm9pc3kpKSxdCiAgcmV0dXJuKHRyYWluaW5nX25vaXN5KQp9CgpnZXRfRUxBX21lYXN1cmUgPC0gZnVuY3Rpb24oQTAsIEF4KXsKICBSTEEgPC0gKEEwIC0gQXgpIC8gQTAKICBGQTAgPC0gKDEwMCAtIEEwKSAvIEEwCiAgRUxBIDwtIFJMQSArIEZBMAogIHJldHVybihFTEEpCn0KCnJhbmRvbUZvcmVzdF9wZXJmb3JtYWNlIDwtIGZ1bmN0aW9uKHRyYWluaW5nX2RhdGEsIHRlc3RpbmdfZGF0YSwgbWV0cmljKXsKICByZkZpdCA8LSB0cmFpbihjbGFzcyB+IHNwK3dwK3ducCtzbnArZHMrZG0rZGwrc3Mrc20rc2wsCiAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluaW5nX2RhdGEsCiAgICAgICAgICAgICAgICAgbWV0cmljPSJST0MiLAogICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJyZiIsCiAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gc2V0dGluZ3MpCiAgcHJlZHNyZnByb2JzIDwtIHByZWRpY3QocmZGaXQsdGVzdGluZ19kYXRhLHR5cGU9J3Byb2InKQogIHByZWRzcmYgPC0gaWZlbHNlKHByZWRzcmZwcm9icyRCb3RuZXQgPj0wLjUsJ0JvdG5ldCcsJ05vcm1hbCcpCiAgY20gPC0gY29uZnVzaW9uTWF0cml4KHByZWRzcmYsdGVzdGluZ19kYXRhJGNsYXNzKQogIHJlc3VsdCA8LSBjbSRieUNsYXNzW21ldHJpY10KICByZXR1cm4ocmVzdWx0KQp9CnRyYWluaW5nCnRlc3RpbmcKYGBgCgojIyMgRGF0YSB0cmFpbmluZyBwYXJ0aXRpb25zOiBjb2xkIHN0YXJ0IHN0dWR5CiMjIyBJdGVyYXRpb24gIzEKYGBge3J9CnNldC5zZWVkKDIwMSkKc2l6ZV90cmFpbmluZyA8LSBucm93KHRyYWluaW5nKQp0cmFpbmluZy5zYW1wbGVkXzEgPC0gdHJhaW5pbmdbc2FtcGxlKHNpemVfdHJhaW5pbmcsIHNpemVfdHJhaW5pbmcpLCBdCgpyZXN1bHQgPC0gY29sZF9zdGFydF9kYXRhKHRyYWluaW5nLnNhbXBsZWRfMSwgdGVzdGluZywgc2V0dGluZ3MgPSBjdHJsX2Zhc3QpCm91dHB1dF8xIDwtIHJlc3VsdCRvdXRwdXQKb3V0cHV0X3RfMSA8LSByZXN1bHQkb3V0cHV0X3QKb3V0cHV0XzEKCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0XzEpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQpmaXJzdF90cmFpbmluZ19zYW1wbGUgPC0gdHJhaW5pbmcuc2FtcGxlZF8xWzE6MjAwLF0KZ2dwbG90KGZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoc3ViY2xhc3MpKQpjbGFzc19kaXN0cmlidXRpb24gPC0gZmlyc3RfdHJhaW5pbmdfc2FtcGxlICU+JSBncm91cF9ieShjbGFzcykgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUgYXJyYW5nZShkZXNjKG4pKQpnZ3Bsb3QoZmlyc3RfdHJhaW5pbmdfc2FtcGxlKSArIGdlb21fYmFyKGFlcyhjbGFzcykpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkKCnRlc3RpbmdfcmVzdWx0IDwtIHJlc3VsdCR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0X3RfMSkKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKb3V0cHV0X3RfYXV4XzEgPC0gb3V0cHV0X3RfMQpuYW1lcyhvdXRwdXRfdF9hdXhfMSkgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpvdXRwdXRfcmVzdWx0XzEgPC0gY2JpbmQob3V0cHV0XzEsb3V0cHV0X3RfYXV4XzEpCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0X3Jlc3VsdF8xKQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAojIyMgSXRlcmF0aW9uICMyCmBgYHtyfQpzZXQuc2VlZCgyMDIpCnNpemVfdHJhaW5pbmcgPC0gbnJvdyh0cmFpbmluZykKdHJhaW5pbmcuc2FtcGxlZF8yIDwtIHRyYWluaW5nW3NhbXBsZShzaXplX3RyYWluaW5nLCBzaXplX3RyYWluaW5nKSwgXQoKcmVzdWx0XzIgPC0gY29sZF9zdGFydF9kYXRhKHRyYWluaW5nLnNhbXBsZWRfMiwgdGVzdGluZywgc2V0dGluZ3MgPSBjdHJsX2Zhc3QpCm91dHB1dF8yIDwtIHJlc3VsdF8yJG91dHB1dApvdXRwdXRfdF8yIDwtIHJlc3VsdF8yJG91dHB1dF90Cm91dHB1dF8yCgpnZyA8LSBnZ3Bsb3QoZGF0YSA9IG91dHB1dF8yKQogIGdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICAgIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICAgI3N1YnRpdGxlPSJEcmF3biBmcm9tIExvbmcgRGF0YSBmb3JtYXQiLCAKICAgICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgICAgY29sb3I9TlVMTCkKZmlyc3RfdHJhaW5pbmdfc2FtcGxlIDwtIHRyYWluaW5nLnNhbXBsZWRfMlsxOjIwMCxdCmdncGxvdChmaXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKY2xhc3NfZGlzdHJpYnV0aW9uIDwtIGZpcnN0X3RyYWluaW5nX3NhbXBsZSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZ2dwbG90KGZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoY2xhc3MpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgp0ZXN0aW5nX3Jlc3VsdF8yIDwtIHJlc3VsdCR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0X3RfMikKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKb3V0cHV0X3RfYXV4XzIgPC0gb3V0cHV0X3RfMgpuYW1lcyhvdXRwdXRfdF9hdXhfMikgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpvdXRwdXRfcmVzdWx0XzIgPC0gY2JpbmQob3V0cHV0XzIsb3V0cHV0X3RfYXV4XzIpCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0X3Jlc3VsdF8yKQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAoKIyMjIEl0ZXJhdGlvbiAjMwpgYGB7cn0Kc2V0LnNlZWQoMjMzKQpzaXplX3RyYWluaW5nIDwtIG5yb3codHJhaW5pbmcpCnRyYWluaW5nLnNhbXBsZWRfMyA8LSB0cmFpbmluZ1tzYW1wbGUoc2l6ZV90cmFpbmluZywgc2l6ZV90cmFpbmluZyksIF0KCnJlc3VsdF8zIDwtIGNvbGRfc3RhcnRfZGF0YSh0cmFpbmluZy5zYW1wbGVkXzMsIHRlc3RpbmcsIHNldHRpbmdzID0gY3RybF9mYXN0KQpvdXRwdXRfMyA8LSByZXN1bHRfMyRvdXRwdXQKb3V0cHV0X3RfMyA8LSByZXN1bHRfMyRvdXRwdXRfdApvdXRwdXRfMwoKCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0XzMpCiAgZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdyZWQnKSArIAogICAgbGFicyh0aXRsZT0iUmFuZG9tIEZvcmVzdCB0aHJvdWdoIGRhdGEgdHJhaW5pbmcgc2l6ZSIsIAogICAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgICB5PSJGMSBTY29yZSIsIAogICAgICAgICBjb2xvcj1OVUxMKQpmaXJzdF90cmFpbmluZ19zYW1wbGUgPC0gdHJhaW5pbmcuc2FtcGxlZF8zWzE6MjAwLF0KZ2dwbG90KGZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoc3ViY2xhc3MpKQpjbGFzc19kaXN0cmlidXRpb24gPC0gZmlyc3RfdHJhaW5pbmdfc2FtcGxlICU+JSBncm91cF9ieShjbGFzcykgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUgYXJyYW5nZShkZXNjKG4pKQpnZ3Bsb3QoZmlyc3RfdHJhaW5pbmdfc2FtcGxlKSArIGdlb21fYmFyKGFlcyhjbGFzcykpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkKCnRlc3RpbmdfcmVzdWx0XzMgPC0gcmVzdWx0JHRlc3RpbmdfcmVzdWx0CiN0ZXN0aW5nX3Jlc3VsdAoKZ2cgPC0gZ2dwbG90KGRhdGEgPSBvdXRwdXRfdF8zKQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCgpvdXRwdXRfdF9hdXhfMyA8LSBvdXRwdXRfdF8zCm5hbWVzKG91dHB1dF90X2F1eF8zKSA8LSBjKCdkYXRhX2NvdW50X3QnLCdtZXRyaWNfdCcpCm91dHB1dF9yZXN1bHRfMyA8LSBjYmluZChvdXRwdXRfMyxvdXRwdXRfdF9hdXhfMykKZ2cgPC0gZ2dwbG90KGRhdGEgPSBvdXRwdXRfcmVzdWx0XzMpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50X3QsIHkgPSBtZXRyaWNfdCksY29sb3IgPSAnYmx1ZScpICsgCiAgbGFicyh0aXRsZT0iUmFuZG9tIEZvcmVzdCB0aHJvdWdoIGRhdGEgdHJhaW5pbmcgc2l6ZSIsIAogICAgICAgI3N1YnRpdGxlPSJEcmF3biBmcm9tIExvbmcgRGF0YSBmb3JtYXQiLCAKICAgICAgIGNhcHRpb249IlNvdXJjZTogQ1RVLTEzIiwgCiAgICAgICB5PSJGMSBTY29yZSIsIAogICAgICAgY29sb3I9TlVMTCkKYGBgCgojIyMgSXRlcmF0aW9uICM0CmBgYHtyfQpzZXQuc2VlZCgyMDQpCnNpemVfdHJhaW5pbmcgPC0gbnJvdyh0cmFpbmluZykKdHJhaW5pbmcuc2FtcGxlZF80IDwtIHRyYWluaW5nW3NhbXBsZShzaXplX3RyYWluaW5nLCBzaXplX3RyYWluaW5nKSwgXQoKcmVzdWx0XzQgPC0gY29sZF9zdGFydF9kYXRhKHRyYWluaW5nLnNhbXBsZWRfNCwgdGVzdGluZywgc2V0dGluZ3MgPSBjdHJsX2Zhc3QpCm91dHB1dF80IDwtIHJlc3VsdF80JG91dHB1dApvdXRwdXRfdF80IDwtIHJlc3VsdF80JG91dHB1dF90Cm91dHB1dF80CgpnZyA8LSBnZ3Bsb3QoZGF0YSA9IG91dHB1dF80KQogIGdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICAgIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICAgI3N1YnRpdGxlPSJEcmF3biBmcm9tIExvbmcgRGF0YSBmb3JtYXQiLCAKICAgICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgICAgY29sb3I9TlVMTCkKZmlyc3RfdHJhaW5pbmdfc2FtcGxlIDwtIHRyYWluaW5nLnNhbXBsZWRfNFsxOjIwMCxdCmdncGxvdChmaXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKY2xhc3NfZGlzdHJpYnV0aW9uIDwtIGZpcnN0X3RyYWluaW5nX3NhbXBsZSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZ2dwbG90KGZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoY2xhc3MpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgp0ZXN0aW5nX3Jlc3VsdF80IDwtIHJlc3VsdCR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0X3RfNCkKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKb3V0cHV0X3RfYXV4XzQgPC0gb3V0cHV0X3RfNApuYW1lcyhvdXRwdXRfdF9hdXhfNCkgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpvdXRwdXRfcmVzdWx0XzQgPC0gY2JpbmQob3V0cHV0XzQsb3V0cHV0X3RfYXV4XzQpCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0X3Jlc3VsdF80KQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAoKIyMjIEl0ZXJhdGlvbiAjNQpgYGB7cn0Kc2V0LnNlZWQoMjA1KQpzaXplX3RyYWluaW5nIDwtIG5yb3codHJhaW5pbmcpCnRyYWluaW5nLnNhbXBsZWRfNSA8LSB0cmFpbmluZ1tzYW1wbGUoc2l6ZV90cmFpbmluZywgc2l6ZV90cmFpbmluZyksIF0KCnJlc3VsdF81IDwtIGNvbGRfc3RhcnRfZGF0YSh0cmFpbmluZy5zYW1wbGVkXzUsIHRlc3RpbmcsIHNldHRpbmdzID0gY3RybF9mYXN0KQpvdXRwdXRfNSA8LSByZXN1bHRfNSRvdXRwdXQKb3V0cHV0X3RfNSA8LSByZXN1bHRfNSRvdXRwdXRfdApvdXRwdXRfNQoKZ2cgPC0gZ2dwbG90KGRhdGEgPSBvdXRwdXRfNSkKICBnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgCiAgICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICAgIGNhcHRpb249IlNvdXJjZTogQ1RVLTEzIiwgCiAgICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICAgIGNvbG9yPU5VTEwpCmZpcnN0X3RyYWluaW5nX3NhbXBsZSA8LSB0cmFpbmluZy5zYW1wbGVkXzVbMToyMDAsXQpnZ3Bsb3QoZmlyc3RfdHJhaW5pbmdfc2FtcGxlKSArIGdlb21fYmFyKGFlcyhzdWJjbGFzcykpCmNsYXNzX2Rpc3RyaWJ1dGlvbiA8LSBmaXJzdF90cmFpbmluZ19zYW1wbGUgJT4lIGdyb3VwX2J5KGNsYXNzKSAlPiUgc3VtbWFyaXNlKG4gPSBuKCkpICU+JSBhcnJhbmdlKGRlc2MobikpCmdncGxvdChmaXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKGNsYXNzKSkgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKQoKdGVzdGluZ19yZXN1bHRfNSA8LSByZXN1bHQkdGVzdGluZ19yZXN1bHQKI3Rlc3RpbmdfcmVzdWx0CgpnZyA8LSBnZ3Bsb3QoZGF0YSA9IG91dHB1dF90XzUpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAnYmx1ZScpICsgCiAgbGFicyh0aXRsZT0iUmFuZG9tIEZvcmVzdCB0aHJvdWdoIGRhdGEgdHJhaW5pbmcgc2l6ZSIsIAogICAgICAgI3N1YnRpdGxlPSJEcmF3biBmcm9tIExvbmcgRGF0YSBmb3JtYXQiLCAKICAgICAgIGNhcHRpb249IlNvdXJjZTogQ1RVLTEzIiwgCiAgICAgICB5PSJGMSBTY29yZSIsIAogICAgICAgY29sb3I9TlVMTCkKCm91dHB1dF90X2F1eF81IDwtIG91dHB1dF90XzUKbmFtZXMob3V0cHV0X3RfYXV4XzUpIDwtIGMoJ2RhdGFfY291bnRfdCcsJ21ldHJpY190JykKb3V0cHV0X3Jlc3VsdF81IDwtIGNiaW5kKG91dHB1dF81LG91dHB1dF90X2F1eF81KQpnZyA8LSBnZ3Bsb3QoZGF0YSA9IG91dHB1dF9yZXN1bHRfNSkKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdyZWQnKSArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnRfdCwgeSA9IG1ldHJpY190KSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQpgYGAKCiMjIyBEYXRhIHRyYWluaW5nIHBhcnRpdGlvbnM6IGNvbGQgc3RhcnQgc3R1ZHkgKHNpbXBsZSBSYW5kb20gRm9yZXN0KQpgYGB7cn0Kc2V0LnNlZWQoMjExKQpzaXplX3RyYWluaW5nIDwtIG5yb3codHJhaW5pbmcpCnJmX3RyYWluaW5nLnNhbXBsZWRfMSA8LSB0cmFpbmluZ1tzYW1wbGUoc2l6ZV90cmFpbmluZywgc2l6ZV90cmFpbmluZyksIF0KcmZfcmVzdWx0XzEgPC0gY29sZF9zdGFydF9kYXRhX29ubHlfcmYocmZfdHJhaW5pbmcuc2FtcGxlZF8xLCB0ZXN0aW5nLCBzZXR0aW5ncyA9IGN0cmxfZmFzdCkKCnNldC5zZWVkKDIyMikKc2l6ZV90cmFpbmluZyA8LSBucm93KHRyYWluaW5nKQpyZl90cmFpbmluZy5zYW1wbGVkXzIgPC0gdHJhaW5pbmdbc2FtcGxlKHNpemVfdHJhaW5pbmcsIHNpemVfdHJhaW5pbmcpLCBdCnJmX3Jlc3VsdF8yIDwtIGNvbGRfc3RhcnRfZGF0YV9vbmx5X3JmKHJmX3RyYWluaW5nLnNhbXBsZWRfMiwgdGVzdGluZywgc2V0dGluZ3MgPSBjdHJsX2Zhc3QpCgpzZXQuc2VlZCgyMjMpCnNpemVfdHJhaW5pbmcgPC0gbnJvdyh0cmFpbmluZykKcmZfdHJhaW5pbmcuc2FtcGxlZF8zIDwtIHRyYWluaW5nW3NhbXBsZShzaXplX3RyYWluaW5nLCBzaXplX3RyYWluaW5nKSwgXQpyZl9yZXN1bHRfMyA8LSBjb2xkX3N0YXJ0X2RhdGFfb25seV9yZihyZl90cmFpbmluZy5zYW1wbGVkXzMsIHRlc3RpbmcsIHNldHRpbmdzID0gY3RybF9mYXN0KQoKc2V0LnNlZWQoMjI0KQpzaXplX3RyYWluaW5nIDwtIG5yb3codHJhaW5pbmcpCnJmX3RyYWluaW5nLnNhbXBsZWRfNCA8LSB0cmFpbmluZ1tzYW1wbGUoc2l6ZV90cmFpbmluZywgc2l6ZV90cmFpbmluZyksIF0KcmZfcmVzdWx0XzQgPC0gY29sZF9zdGFydF9kYXRhX29ubHlfcmYocmZfdHJhaW5pbmcuc2FtcGxlZF80LCB0ZXN0aW5nLCBzZXR0aW5ncyA9IGN0cmxfZmFzdCkKCnNldC5zZWVkKDIyNSkKc2l6ZV90cmFpbmluZyA8LSBucm93KHRyYWluaW5nKQpyZl90cmFpbmluZy5zYW1wbGVkXzUgPC0gdHJhaW5pbmdbc2FtcGxlKHNpemVfdHJhaW5pbmcsIHNpemVfdHJhaW5pbmcpLCBdCnJmX3Jlc3VsdF81IDwtIGNvbGRfc3RhcnRfZGF0YV9vbmx5X3JmKHJmX3RyYWluaW5nLnNhbXBsZWRfNSwgdGVzdGluZywgc2V0dGluZ3MgPSBjdHJsX2Zhc3QpCgpyZl9kYXRhLnJlc3VsdCA8LSBkYXRhLmZyYW1lKHJmX3Jlc3VsdF81JG91dHB1dCRkYXRhX2NvdW50KQpyZl9kYXRhLnJlc3VsdF90IDwtIGRhdGEuZnJhbWUocmZfcmVzdWx0XzUkb3V0cHV0JGRhdGFfY291bnQpCmZvcihpIGluIGMoMTozMCkpewogIGN1cnJlbnRfc2VlZCA8LSAyMjYgKyBpCiAgc2V0LnNlZWQoY3VycmVudF9zZWVkKQogICNzaXplX3RyYWluaW5nIDwtIG5yb3codHJhaW5pbmcpCiAgcmZfdHJhaW5pbmcuc2FtcGxlZF9jdXJyZW50IDwtIHRyYWluaW5nW3NhbXBsZShzaXplX3RyYWluaW5nLCBzaXplX3RyYWluaW5nKSwgXQogIHJmX3Jlc3VsdF9jdXJyZW50IDwtIGNvbGRfc3RhcnRfZGF0YV9vbmx5X3JmKHJmX3RyYWluaW5nLnNhbXBsZWRfY3VycmVudCwgdGVzdGluZywgc2V0dGluZ3MgPSBjdHJsX2Zhc3QpCiAgCiAgcmZfZGF0YS5yZXN1bHQgPC0gY2JpbmQocmZfZGF0YS5yZXN1bHQscmZfcmVzdWx0X2N1cnJlbnQkb3V0cHV0JG1ldHJpYykKICByZl9kYXRhLnJlc3VsdF90IDwtIGNiaW5kKHJmX2RhdGEucmVzdWx0X3QscmZfcmVzdWx0X2N1cnJlbnQkb3V0cHV0X3QkbWV0cmljKQp9CiAKIHggPC0gYygnY291bnRfb2ZfZGF0YScpCiBmb3IoaSBpbiBjKDE6MzApKXsKICAgeFtpKzFdIDwtIHBhc3RlKCdpdGVyYXRpb25fJyx0b1N0cmluZyhpKSxzZXAgPSAiIikKIH0KIHgKIG5hbWVzKHJmX2RhdGEucmVzdWx0KSA8LSB4CiBuYW1lcyhyZl9kYXRhLnJlc3VsdF90KSA8LSB4CiByZl9kYXRhLnJlc3VsdAogcmZfZGF0YS5yZXN1bHRfdCAKIAogI3dyaXRlLnRhYmxlKHJmX2RhdGEucmVzdWx0LGZpbGU9InJhbmRvbV9mb3Jlc3RfMzBfaXRlcmF0aW9uc19mMV90ZXN0aW5nLnR4dCIsc2VwPSJ8Iiwgcm93Lm5hbWVzID0gRikKICN3cml0ZS50YWJsZShyZl9kYXRhLnJlc3VsdF90LGZpbGU9InJhbmRvbV9mb3Jlc3RfMzBfaXRlcmF0aW9uc19mMV90cmFpbmluZy50eHQiLHNlcD0ifCIsIHJvdy5uYW1lcyA9IEYpCmBgYAoKIyMjIEl0ZXJhdGlvbiAjMQpgYGB7cn0KcmZfb3V0cHV0XzEgPC0gcmZfcmVzdWx0XzEkb3V0cHV0CnJmX291dHB1dF90XzEgPC0gcmZfcmVzdWx0XzEkb3V0cHV0X3QKcmZfb3V0cHV0XzEKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0XzEpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfZmlyc3RfdHJhaW5pbmdfc2FtcGxlIDwtIHJmX3RyYWluaW5nLnNhbXBsZWRfMVsxOjIwMCxdCmdncGxvdChyZl9maXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKcmZfY2xhc3NfZGlzdHJpYnV0aW9uIDwtIHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZ2dwbG90KHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoY2xhc3MpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgojcmZfdGVzdGluZ19yZXN1bHRfMSA8LSByZl9yZXN1bHRfMSR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3RfMSkKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfb3V0cHV0X3RfYXV4XzEgPC0gcmZfb3V0cHV0X3RfMQpuYW1lcyhyZl9vdXRwdXRfdF9hdXhfMSkgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpyZl9vdXRwdXRfcmVzdWx0XzEgPC0gY2JpbmQocmZfb3V0cHV0XzEscmZfb3V0cHV0X3RfYXV4XzEpCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3Jlc3VsdF8xKQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAoKIyMjIEl0ZXJhdGlvbiAjMgpgYGB7cn0KcmZfb3V0cHV0XzIgPC0gcmZfcmVzdWx0XzIkb3V0cHV0CnJmX291dHB1dF90XzIgPC0gcmZfcmVzdWx0XzIkb3V0cHV0X3QKcmZfb3V0cHV0XzIKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0XzIpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfZmlyc3RfdHJhaW5pbmdfc2FtcGxlIDwtIHJmX3RyYWluaW5nLnNhbXBsZWRfMlsxOjIwMCxdCmdncGxvdChyZl9maXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKcmZfY2xhc3NfZGlzdHJpYnV0aW9uIDwtIHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZ2dwbG90KHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoY2xhc3MpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgojcmZfdGVzdGluZ19yZXN1bHRfMiA8LSByZl9yZXN1bHRfMiR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3RfMikKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfb3V0cHV0X3RfYXV4XzIgPC0gcmZfb3V0cHV0X3RfMgpuYW1lcyhyZl9vdXRwdXRfdF9hdXhfMikgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpyZl9vdXRwdXRfcmVzdWx0XzIgPC0gY2JpbmQocmZfb3V0cHV0XzIscmZfb3V0cHV0X3RfYXV4XzIpCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3Jlc3VsdF8yKQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAoKIyMjIEl0ZXJhdGlvbiAjMwpgYGB7cn0KcmZfb3V0cHV0XzMgPC0gcmZfcmVzdWx0XzMkb3V0cHV0CnJmX291dHB1dF90XzMgPC0gcmZfcmVzdWx0XzMkb3V0cHV0X3QKcmZfb3V0cHV0XzMKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0XzMpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfZmlyc3RfdHJhaW5pbmdfc2FtcGxlIDwtIHJmX3RyYWluaW5nLnNhbXBsZWRfM1sxOjIwMCxdCmdncGxvdChyZl9maXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKcmZfY2xhc3NfZGlzdHJpYnV0aW9uIDwtIHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZ2dwbG90KHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoY2xhc3MpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgojcmZfdGVzdGluZ19yZXN1bHRfMiA8LSByZl9yZXN1bHRfMiR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3RfMykKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfb3V0cHV0X3RfYXV4XzMgPC0gcmZfb3V0cHV0X3RfMwpuYW1lcyhyZl9vdXRwdXRfdF9hdXhfMykgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpyZl9vdXRwdXRfcmVzdWx0XzMgPC0gY2JpbmQocmZfb3V0cHV0XzMscmZfb3V0cHV0X3RfYXV4XzMpCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3Jlc3VsdF8zKQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAoKIyMjIEl0ZXJhdGlvbiAjNApgYGB7cn0KcmZfb3V0cHV0XzQgPC0gcmZfcmVzdWx0XzQkb3V0cHV0CnJmX291dHB1dF90XzQgPC0gcmZfcmVzdWx0XzQkb3V0cHV0X3QKcmZfb3V0cHV0XzQKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0XzQpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfZmlyc3RfdHJhaW5pbmdfc2FtcGxlIDwtIHJmX3RyYWluaW5nLnNhbXBsZWRfNFsxOjIwMCxdCmdncGxvdChyZl9maXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKcmZfY2xhc3NfZGlzdHJpYnV0aW9uIDwtIHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZ2dwbG90KHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoY2xhc3MpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgojcmZfdGVzdGluZ19yZXN1bHRfMiA8LSByZl9yZXN1bHRfMiR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3RfNCkKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfb3V0cHV0X3RfYXV4XzQgPC0gcmZfb3V0cHV0X3RfNApuYW1lcyhyZl9vdXRwdXRfdF9hdXhfNCkgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpyZl9vdXRwdXRfcmVzdWx0XzQgPC0gY2JpbmQocmZfb3V0cHV0XzQscmZfb3V0cHV0X3RfYXV4XzQpCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3Jlc3VsdF80KQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAoKIyMjIEl0ZXJhdGlvbiAjNQpgYGB7cn0KcmZfb3V0cHV0XzUgPC0gcmZfcmVzdWx0XzUkb3V0cHV0CnJmX291dHB1dF90XzUgPC0gcmZfcmVzdWx0XzUkb3V0cHV0X3QKcmZfb3V0cHV0XzUKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0XzUpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfZmlyc3RfdHJhaW5pbmdfc2FtcGxlIDwtIHJmX3RyYWluaW5nLnNhbXBsZWRfNVsxOjIwMCxdCmdncGxvdChyZl9maXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKcmZfY2xhc3NfZGlzdHJpYnV0aW9uIDwtIHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZ2dwbG90KHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoY2xhc3MpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgojcmZfdGVzdGluZ19yZXN1bHRfMiA8LSByZl9yZXN1bHRfMiR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3RfNSkKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfb3V0cHV0X3RfYXV4XzUgPC0gcmZfb3V0cHV0X3RfNQpuYW1lcyhyZl9vdXRwdXRfdF9hdXhfNSkgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpyZl9vdXRwdXRfcmVzdWx0XzUgPC0gY2JpbmQocmZfb3V0cHV0XzUscmZfb3V0cHV0X3RfYXV4XzUpCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3Jlc3VsdF81KQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAoKCiMjIyBTdHVkaWVzIFNhbXBsZXMKYGBge3J9CmZpcnN0X3RyYWluaW5nX3NhbXBsZSA8LSB0cmFpbmluZy5zYW1wbGVkWzE6MjAwLF0KZmlyc3RfdHJhaW5pbmdfc2FtcGxlCmdncGxvdChmaXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKCmNsYXNzX2Rpc3RyaWJ1dGlvbiA8LSBmaXJzdF90cmFpbmluZ19zYW1wbGUgJT4lIGdyb3VwX2J5KGNsYXNzKSAlPiUgc3VtbWFyaXNlKG4gPSBuKCkpICU+JSBhcnJhbmdlKGRlc2MobikpCmdncGxvdChmaXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKGNsYXNzKSkgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKQoKYGBgCgoKIyMjIHBhcnQgMgpgYGB7cn0Kc2V0LnNlZWQoMjA2KQpsaWJyYXJ5KGRvUGFyYWxsZWwpCmNsIDwtIG1ha2VDbHVzdGVyKDIpCnJlZ2lzdGVyRG9QYXJhbGxlbChjbCkKc2l6ZV90cmFpbmluZyA8LSBucm93KHRyYWluaW5nKQpzcGxpdF9zaXplX3RyYWluaW5nID0gc2l6ZV90cmFpbmluZyAvIDIwMApjb3VudF9yYW5kb20gPC0gZm9yZWFjaChpPTE6c3BsaXRfc2l6ZV90cmFpbmluZykgJWRvcGFyJSB7CiAgMjAwICogaQp9CnRyYWluaW5nLnNhbXBsZWQgPC0gdHJhaW5pbmdbc2FtcGxlKHNpemVfdHJhaW5pbmcsIHNpemVfdHJhaW5pbmcpLCBdCm1ldHJpYyA8LSBmb3JlYWNoKGk9MTpzcGxpdF9zaXplX3RyYWluaW5nKSAlZG8lIHsKICAjbGlicmFyeShjYXJldCkKICBjb3VudCA8LSAyMDAgKiBpCiAgYXV4X3RyYWluaW5nX3NldCA8LSB0cmFpbmluZy5zYW1wbGVkW2MoMTpjb3VudCksIF0jdHJhaW5pbmdbc2FtcGxlKHNpemVfdHJhaW5pbmcsIGNvdW50KSwgXQogIGNsdXN0ZXJzIDwtIGttZWFucyhhdXhfdHJhaW5pbmdfc2V0WywtYygxMSwxMiwxMywxNCldLDMsbnN0YXJ0ID0gMjUpCiAgYXV4X3RyYWluaW5nX3NldF9jbHVzdGVyIDwtIGNiaW5kKGF1eF90cmFpbmluZ19zZXQsIGNsdXN0ZXIgPSBjbHVzdGVycyRjbHVzdGVyKQogIHJlc3VsdF92ZWN0b3IgPC0gbnVtZXJpYyhucm93KHRlc3RpbmcpKQogIGZvciAoaiBpbiBjKDE6MykpewogICAgY2x1c3Rlcl9kYXRhIDwtIGZpbHRlcihhdXhfdHJhaW5pbmdfc2V0X2NsdXN0ZXIsIGNsdXN0ZXIgPT0gaikKICAgIG5ld19yZkZpdCA8LSB0cmFpbihjbGFzcyB+IHNwK3dwK3ducCtzbnArZHMrZG0rZGwrc3Mrc20rc2wsCiAgICAgICAgICAgICAgIGRhdGEgPSBjbHVzdGVyX2RhdGEsCiAgICAgICAgICAgICAgIG1ldHJpYz0iUk9DIiwKICAgICAgICAgICAgICAgbWV0aG9kID0gInJmIiwKICAgICAgICAgICAgICAgdHJDb250cm9sID0gY3RybF9mYXN0KQogICAgcHJlZHNyZnByb2JzIDwtIHByZWRpY3QobmV3X3JmRml0LHRlc3RpbmcsdHlwZT0ncHJvYicpCiAgICBmb3IgKGsgaW4gYygxOmxlbmd0aChyZXN1bHRfdmVjdG9yKSkpewogICAgICBpZihwcmVkc3JmcHJvYnMkQm90bmV0W2tdID4gMC41KXsKICAgICAgICByZXN1bHRfdmVjdG9yW2tdIDwtIHJlc3VsdF92ZWN0b3Jba10gKyAxCiAgICAgIH0KICAgICAgZWxzZXsKICAgICAgICByZXN1bHRfdmVjdG9yW2tdIDwtIHJlc3VsdF92ZWN0b3Jba10gLSAxCiAgICAgIH0KICAgIH0KICAgIAogIH0KICBhID0gaWZlbHNlKHJlc3VsdF92ZWN0b3IgPiAwLCdCb3RuZXQnLCdOb3JtYWwnKQogIGNtIDwtIGNvbmZ1c2lvbk1hdHJpeChhLHRlc3RpbmckY2xhc3MpCiAgbWV0cmljIDwtIGNtJGJ5Q2xhc3NbJ0YxJ10jY20kb3ZlcmFsbFsxXQogIG1ldHJpYwogIAp9CgpvdXRwdXQgPC0gZG8uY2FsbChyYmluZCwgTWFwKGRhdGEuZnJhbWUsIGRhdGFfY291bnQ9Y291bnRfcmFuZG9tLCBtZXRyaWM9bWV0cmljKSkKb3V0cHV0CmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0KQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgCiAgbGFicyh0aXRsZT0iUmFuZG9tIEZvcmVzdCB0aHJvdWdoIGRhdGEgdHJhaW5pbmcgc2l6ZSIsIAogICAgICAgI3N1YnRpdGxlPSJEcmF3biBmcm9tIExvbmcgRGF0YSBmb3JtYXQiLCAKICAgICAgIGNhcHRpb249IlNvdXJjZTogQ1RVLTEzIiwgCiAgICAgICB5PSJBY2N1cmFjeSIsIAogICAgICAgY29sb3I9TlVMTCkKY2x1c3Rlcl9kYXRhCmBgYAoKCiMjIyBUZXN0IHdpdGggb25seSBvbmUKYGBge3J9CnNldC5zZWVkKDIyNikKc2l6ZV90cmFpbmluZyA8LSBucm93KHRyYWluaW5nKQp0cmFpbmluZy5zYW1wbGVkIDwtIHRyYWluaW5nW3NhbXBsZShzaXplX3RyYWluaW5nLCBzaXplX3RyYWluaW5nKSwgXQoKYXV4X3RyYWluaW5nX3NldCA8LSB0cmFpbmluZy5zYW1wbGVkW2MoMToyMDApLCBdI3RyYWluaW5nW3NhbXBsZShzaXplX3RyYWluaW5nLCAyMDApLCBdCmNsdXN0ZXJzIDwtIGttZWFucyhhdXhfdHJhaW5pbmdfc2V0WywtYygxMSwxMiwxMywxNCldLDMsbnN0YXJ0ID0gMjUpCmF1eF90cmFpbmluZ19zZXRfY2x1c3RlciA8LSBjYmluZChhdXhfdHJhaW5pbmdfc2V0LCBjbHVzdGVyID0gY2x1c3RlcnMkY2x1c3RlcikKcmVzdWx0X3ZlY3RvciA8LSBudW1lcmljKG5yb3codGVzdGluZykpCnJlc3VsdF92ZWN0b3JfdHJhaW5uaW5nIDwtIG51bWVyaWMobnJvdyhhdXhfdHJhaW5pbmdfc2V0KSkKCmZvciAoaiBpbiBjKDE6MykpewogIGNsdXN0ZXJfZGF0YSA8LSBhdXhfdHJhaW5pbmdfc2V0X2NsdXN0ZXIgJT4lIGZpbHRlcihjbHVzdGVyID09IGopCiAgbmV3X3JmRml0IDwtIHRyYWluKHN1YmNsYXNzIH4gc3Ard3Ard25wK3NucCtkcytkbStkbCtzcytzbStzbCwKICAgICAgICAgICAgICAgZGF0YSA9IGNsdXN0ZXJfZGF0YSwKICAgICAgICAgICAgICAgbWV0cmljPSJST0MiLAogICAgICAgICAgICAgICBtZXRob2QgPSAicmYiLAogICAgICAgICAgICAgICB0ckNvbnRyb2wgPSBjdHJsX2Zhc3QpCiAgcHJlZHNyZnByb2JzIDwtIHByZWRpY3QobmV3X3JmRml0LHRlc3RpbmcsdHlwZT0ncHJvYicpCiAgZm9yIChrIGluIGMoMTpsZW5ndGgocmVzdWx0X3ZlY3RvcikpKXsKICAgIGlmKHByZWRzcmZwcm9icyRib3RuZXRba10gPiAwLjUpewogICAgICByZXN1bHRfdmVjdG9yW2tdIDwtIHJlc3VsdF92ZWN0b3Jba10gKyAxCiAgICB9CiAgICBlbHNlewogICAgICByZXN1bHRfdmVjdG9yW2tdIDwtIHJlc3VsdF92ZWN0b3Jba10gLSAxCiAgICB9CiAgfQogIAogICNUcmFpbm5pbmcgcHJlZGljdAogIHByZWRzcmZwcm9ic190IDwtIHByZWRpY3QobmV3X3JmRml0LGF1eF90cmFpbmluZ19zZXQsdHlwZT0ncHJvYicpCiAgZm9yIChrIGluIGMoMTpsZW5ndGgocmVzdWx0X3ZlY3Rvcl90cmFpbm5pbmcpKSl7CiAgICBpZihwcmVkc3JmcHJvYnNfdCRib3RuZXRba10gPiAwLjUpewogICAgICByZXN1bHRfdmVjdG9yX3RyYWlubmluZ1trXSA8LSByZXN1bHRfdmVjdG9yX3RyYWlubmluZ1trXSArIDEKICAgIH0KICAgIGVsc2V7CiAgICAgIHJlc3VsdF92ZWN0b3JfdHJhaW5uaW5nW2tdIDwtIHJlc3VsdF92ZWN0b3JfdHJhaW5uaW5nW2tdIC0gMQogICAgfQogIH0KfQoKYSA9IGlmZWxzZShyZXN1bHRfdmVjdG9yID4gMCwnYm90bmV0Jywnbm9ybWFsJykKYiA8LSBpZmVsc2UocmVzdWx0X3ZlY3Rvcl90cmFpbm5pbmcgPiAwLCdib3RuZXQnLCdub3JtYWwnKQpjbSA8LSBjb25mdXNpb25NYXRyaXgoYSx0ZXN0aW5nJHN1YmNsYXNzKQptZXRyaWMgPC0gY20kYnlDbGFzc1snRjEnXSNjbSRvdmVyYWxsWzFdCm1ldHJpYwpjbV90IDwtIGNvbmZ1c2lvbk1hdHJpeChiLGF1eF90cmFpbmluZ19zZXQkc3ViY2xhc3MpCm1ldHJpY190IDwtIGNtX3QkYnlDbGFzc1snRjEnXQptZXRyaWNfdApgYGAKCiMjIyBTYW1wbGUgZXhhbXBsZXMKYGBge3J9CnNldC5zZWVkKDU1NikKYSA9IGMoMSwyLDMsNCw1LDYsNyw4LDkpCnIgPC0gc2FtcGxlKDksMykKYVtyXQpyMiA8LSBzYW1wbGUoOSwzKQphW3IyXQpgYGAKCmBgYHtyfQojdGVzdGluZ19yZXN1bHQKdGVzdGluZ19yZXN1bHQuYmtwIDwtIHRlc3RpbmdfcmVzdWx0CnRlc3RpbmdfcmVzdWx0Cm5hbWVzX2F1eCA8LSBmb3JlYWNoKGk9MToobnJvdyh0cmFpbmluZykvMjAwKSkgJWRvJSB7CiAgICBpdGVyYXRpb24gPC0gMjAwICogaQogICAgcGFzdGUoJ3NpemVfJyx0b1N0cmluZyhpdGVyYXRpb24pLHNlcCA9ICIiKQp9CnRlc3RpbmdfcmVzdWx0X25hbWVzIDwtIHVubGlzdChuYW1lc19hdXgsIHVzZS5uYW1lcz1GQUxTRSkKdGVzdGluZ19yZXN1bHQgPC0gdGVzdGluZ19yZXN1bHRbLGMoLTEpXQpuYW1lcyh0ZXN0aW5nX3Jlc3VsdCkgPC0gdGVzdGluZ19yZXN1bHRfbmFtZXMKdGVzdGluZ19yZXN1bHQKCnRlc3RpbmdfYXV4IDwtIGNiaW5kKHRlc3RpbmcsdGVzdGluZ19yZXN1bHQpCnRlc3RpbmdfYXV4LmJrcDIgPC0gdGVzdGluZ19hdXgKI3dyaXRlLnRhYmxlKHRlc3RpbmdfYXV4LGZpbGU9InRlc3RpbmdfY2x1c3Rlcl9yZXN1bHQudHh0IixzZXA9InwiLCByb3cubmFtZXMgPSBGKQp0ZXN0aW5nX2F1eApzdW1zIDwtIHJvd1N1bXModGVzdGluZ19hdXhbLC1jKDE6MTQpXSkKc3Vtcwp0ZXN0aW5nX2F1eFssLWMoMToxNCldCnRlc3RpbmdfYXV4IDwtIGNiaW5kKHRlc3RpbmdfYXV4LHN1bXMpCnRlc3RpbmdfYXV4CnRlc3RpbmdfYXV4X3Jlc3VsdCA8LSB0ZXN0aW5nX2F1eCAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSwgc3VtcyA9IHN1bShzdW1zKSkgJT4lIGFycmFuZ2UoZGVzYyhzdW1zKSkKdGVzdGluZ19hdXhfcmVzdWx0CgpncmFwaF90ZXN0aW5nX3Jlc3VsdCA8LSBnZ3Bsb3QodGVzdGluZ19hdXhfcmVzdWx0Wy1jKDEsbnJvdyh0ZXN0aW5nX2F1eF9yZXN1bHQpKSxdKQpncmFwaF90ZXN0aW5nX3Jlc3VsdCArIGdlb21fcG9pbnQoYWVzKGNsYXNzLHN1bXMpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgpmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZAoKbGlicmFyeShncmlkRXh0cmEpCnBkZigiZGF0YV9vdXRwdXQucGRmIiwgaGVpZ2h0PTExLCB3aWR0aD04LjUpCmdyaWQudGFibGUoZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWRbMToyMCxdKQpkZXYub2ZmKCkKCnRlc3RpbmdfcmVzdWx0LmJrcAp0ZXN0aW5nX2F1eC5ia3AyCnRlc3RpbmdfYXV4X3Jlc3VsdAoKcnVzdHlfZGF0YV9yZXN1bHQgPC0gdGVzdGluZ19hdXguYmtwMgpydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydCA8LSBydXN0eV9kYXRhX3Jlc3VsdFssLWMoMToxMSwxNCldCnJ1c3R5X2RhdGFfcmVzdWx0X3Nob3J0WywtYygxLDIpXQpydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydCRwb3MgPC0gcm93U3VtcyhydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydFssLWMoMSwyKV0gPiAwKQpydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydCRuZWcgPC0gcm93U3VtcyhydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydFssLWMoMSwyKV0gPCAwKQpydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydF9jbGVhbmVkIDwtIHJ1c3R5X2RhdGFfcmVzdWx0X3Nob3J0WyxjKDEsMiw0Niw0NyldCnJ1c3R5X2RhdGFfcmVzdWx0X3Nob3J0X2NsZWFuZWQKcnVzdHlfZGF0YV9yZXN1bHRfc2hvcnRfY2xlYW5lZF9yZXN1bHQgPC0gcnVzdHlfZGF0YV9yZXN1bHRfc2hvcnRfY2xlYW5lZCAlPiUgbXV0YXRlKGdvb2QgPSBpZmVsc2Uoc3ViY2xhc3MgPT0gJ25vcm1hbCcsbmVnLHBvcykpCnJ1c3R5X2RhdGFfcmVzdWx0X3Nob3J0X2NsZWFuZWRfcmVzdWx0IDwtIHJ1c3R5X2RhdGFfcmVzdWx0X3Nob3J0X2NsZWFuZWRfcmVzdWx0ICU+JSBtdXRhdGUoYmFkID0gaWZlbHNlKHN1YmNsYXNzID09ICdub3JtYWwnLHBvcyxuZWcpKQpydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydF9jbGVhbmVkX3Jlc3VsdCAlPiUgZ3JvdXBfYnkocG9ydCkgJT4lIHN1bW1hcmlzZShuPW4oKSxnb29kID0gc3VtKGdvb2QpLGJhZCA9IHN1bShiYWQpKSAlPiUgYXJyYW5nZShkZXNjKG4pKQoKZGF0YV9ib3RuZXRfcG9ydCA8LSBydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydF9jbGVhbmVkX3Jlc3VsdCAlPiUgZmlsdGVyKHN1YmNsYXNzID09ICdib3RuZXQnKQpkYXRhX25vcm1hbF9wb3J0IDwtIHJ1c3R5X2RhdGFfcmVzdWx0X3Nob3J0X2NsZWFuZWRfcmVzdWx0ICU+JSBmaWx0ZXIoc3ViY2xhc3MgPT0gJ25vcm1hbCcpCmRhdGFfYm90bmV0X3BvcnRfcmVzdWx0IDwtICBkYXRhX2JvdG5ldF9wb3J0ICU+JSBncm91cF9ieShwb3J0KSAlPiUgc3VtbWFyaXNlKG49bigpLGdvb2QgPSBzdW0oZ29vZCksYmFkID0gc3VtKGJhZCkpICU+JSBhcnJhbmdlKGRlc2MobikpCmRhdGFfbm9ybWFsX3BvcnRfcmVzdWx0IDwtIGRhdGFfbm9ybWFsX3BvcnQgJT4lIGdyb3VwX2J5KHBvcnQpICU+JSBzdW1tYXJpc2Uobj1uKCksZ29vZCA9IHN1bShnb29kKSxiYWQgPSBzdW0oYmFkKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZGF0YV9ib3RuZXRfcG9ydF9yZXN1bHQKZGF0YV9ub3JtYWxfcG9ydF9yZXN1bHQKCmdncGxvdChkYXRhID0gZGF0YV9ib3RuZXRfcG9ydF9yZXN1bHQpICsgCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gcG9ydCwgZmlsbCA9IGNsYXJpdHkpKQoKI3dyaXRlLnRhYmxlKGRhdGFfYm90bmV0X3BvcnRfcmVzdWx0LGZpbGU9ImRhdGFfYm90bmV0X3BvcnQudHh0IixzZXA9InwiLCByb3cubmFtZXMgPSBGKQpsaWJyYXJ5KHJlc2hhcGUyKQpkYXRhIDwtIGRhdGFfYm90bmV0X3BvcnRfcmVzdWx0CmRhdGEkcG9ydCA8LSBhcy5mYWN0b3IoZGF0YSRwb3J0KQoKbWVsdChkYXRhWyxjKDEsMyw0KV0pCgpnZ3Bsb3QobWVsdChkYXRhWyxjKDEsMyw0KV0pKSsKICBnZW9tX2NvbChhZXMoeD1wb3J0LHk9dmFsdWUsZmlsbD12YXJpYWJsZSkpKwogICN0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCmBgYAoKI01ha2luZyBOb2lzeSBkYXRhICh0cmFpbmluZ19ub2lzeTogZGF0YXNldCB0byB0cmFpbiB3aXRoIDIwJSBvZiBub2lzeSkKYGBge3J9CnNldC5zZWVkKDEwMSkgCnRyYWluaW5nLmJrcCA8LSB0cmFpbmluZwpub2lzeV9kYXRhIDwtIHRyYWluaW5nCgpwb3JjZW50IDwtIG5yb3codHJhaW5pbmcpIC8gNQp0cmFpbmluZ19ub2lzeSA8LSBnZW5lcmF0ZV9kYXRhX25vaXN5KG5vaXN5X2RhdGEscG9yY2VudCkKbnJvdyh0cmFpbmluZykKbnJvdyh0cmFpbmluZ19ub2lzeSkKYGBgCgpgYGB7cn0KcmZGaXQgPC0gdHJhaW4oY2xhc3MgfiBzcCt3cCt3bnArc25wK2RzK2RtK2RsK3NzK3NtK3NsLAogICAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbmluZywKICAgICAgICAgICAgICAgICBtZXRyaWM9IlJPQyIsCiAgICAgICAgICAgICAgICAgbWV0aG9kID0gInJmIiwKICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSBzZXR0aW5ncykKcHJlZHNyZnByb2JzIDwtIHByZWRpY3QocmZGaXQsdGVzdGluZyx0eXBlPSdwcm9iJykKcHJlZHNyZiA8LSBpZmVsc2UocHJlZHNyZnByb2JzJEJvdG5ldCA+PTAuNSwnQm90bmV0JywnTm9ybWFsJykKY20gPC0gY29uZnVzaW9uTWF0cml4KHByZWRzcmYsdGVzdGluZyRjbGFzcykKcmVzdWx0IDwtIGNtJGJ5Q2xhc3NbMTFdCmNtJG92ZXJhbGxbMV0KYGBgCgojUm9idXN0bmVzcyBBbmFsaXN5cwpgYGB7cn0Kc2V0LnNlZWQoMzIxKQpwYXJ0aXRpb25zIDwtIGMoMToxNSkKcmxhX21lYXN1cmVfcmVzdWx0IDwtIGMoKQp0b3RhbCA8LSBucm93KHRyYWluaW5nKQpiYWxhbmNlZF9hY2N1cmFjeSA8LSByYW5kb21Gb3Jlc3RfcGVyZm9ybWFjZSh0cmFpbmluZyx0ZXN0aW5nLCdCYWxhbmNlZCBBY2N1cmFjeScpCgpmb3IoaSBpbiBwYXJ0aXRpb25zKXsKICBwb3JjZW50IDwtIChpKnRvdGFsKSAvIDEwMAogIHRyYWluaW5nX25vaXN5IDwtIGdlbmVyYXRlX2RhdGFfbm9pc3kobm9pc3lfZGF0YSxwb3JjZW50KQogIGJhbGFuY2VkX2FjY3VyYWN5X2F1eCA8LSByYW5kb21Gb3Jlc3RfcGVyZm9ybWFjZSh0cmFpbmluZ19ub2lzeSx0ZXN0aW5nLCdCYWxhbmNlZCBBY2N1cmFjeScpCiAgcmxhX21lYXN1cmVfcmVzdWx0W2ldIDwtIGJhbGFuY2VkX2FjY3VyYWN5X2F1eAp9CnJsYV9tZWFzdXJlX3Jlc3VsdAoKcGxvdChybGFfbWVhc3VyZV9yZXN1bHQpCmBgYAoKYGBge3J9CnNldC5zZWVkKDMyMikKcGFydGl0aW9ucyA8LSBzZXEoMiwzMCwyKQpybGFfbWVhc3VyZV9yZXN1bHRfMiA8LSBjKCkKdG90YWwgPC0gbnJvdyh0cmFpbmluZykKI2JhbGFuY2VkX2FjY3VyYWN5IDwtIHJhbmRvbUZvcmVzdF9wZXJmb3JtYWNlKHRyYWluaW5nLHRlc3RpbmcsJ0JhbGFuY2VkIEFjY3VyYWN5JykKCmZvcihpIGluIHBhcnRpdGlvbnMpewogIHBvcmNlbnQgPC0gKGkqdG90YWwpIC8gMTAwCiAgdHJhaW5pbmdfbm9pc3kgPC0gZ2VuZXJhdGVfZGF0YV9ub2lzeShub2lzeV9kYXRhLHBvcmNlbnQpCiAgYmFsYW5jZWRfYWNjdXJhY3lfYXV4IDwtIHJhbmRvbUZvcmVzdF9wZXJmb3JtYWNlKHRyYWluaW5nX25vaXN5LHRlc3RpbmcsJ0JhbGFuY2VkIEFjY3VyYWN5JykKICBybGFfbWVhc3VyZV9yZXN1bHRfMltpXSA8LSBiYWxhbmNlZF9hY2N1cmFjeV9hdXgKfQpybGFfbWVhc3VyZV9yZXN1bHRfMgoKcGxvdChybGFfbWVhc3VyZV9yZXN1bHRfMikKYGBgCgpgYGB7cn0KaW5kZXggPC0gc2VxKDIsMzAsMikKbWVhc3VyZV9yZXN1bHQgPC0gcmxhX21lYXN1cmVfcmVzdWx0XzJbaW5kZXhdCnJsYV9tZWFzdXJlX2RhdGEgPC0gZGF0YS5mcmFtZShpbmRleCxtZWFzdXJlX3Jlc3VsdCkKbmFtZXMocmxhX21lYXN1cmVfZGF0YSkgPC0gYygnbm9pc2VfcG9yY2VudCcsJ3JsYV9tZWFzdXJlJykKCmdncGxvdChybGFfbWVhc3VyZV9kYXRhKSArIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gbm9pc2VfcG9yY2VudCwgeSA9IHJsYV9tZWFzdXJlKSkgKyBnZW9tX3Ntb290aChtYXBwaW5nID0gYWVzKHggPSBub2lzZV9wb3JjZW50LCB5ID0gcmxhX21lYXN1cmUpKQpgYGA=